#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>

int main(int argc,char* argv[])
{
  if(argc != 3)
  {
    printf("./udp_socket 192.168.2.2 10000\n");
  }
  //从运行参数中提取 ip地址 和 端口
  char* ip=argv[1];
  uint16_t port = atoi(argv[2]);
  //1. 创建套接字
  int sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
  if(sockfd<0)
  {
    perror("socket error");
    return -1;
  }

  //2. 绑定套接字
  struct sockaddr_in addr;           //定义一个ipv4地址结构
  //对addr这个地址中的数据进行赋值
  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
  addr.sin_addr.s_addr=inet_addr(ip);
  socklen_t len = sizeof(struct sockaddr_in);
  //将套接字绑定为addr这个地址上
  int ret = bind(sockfd,(struct sockaddr*)&addr,len);
  if(ret==-1)
  {
    perror("bind error");
    return -1;
  }

  //3. 循环接收发送数据
  while(1)
  {
    // 接收数据
    char buf[1024]={0};
    struct sockaddr_in peer;   //定义一个ipv4地址结构，用于保存数据从哪发送过来
    socklen_t len = sizeof(struct sockaddr_in);    //想要接收数据的长度，是一个输入输出参数
    int ret = recvfrom(sockfd,buf,1023,0,(struct sockaddr*)&peer,&len);
    if(ret<0)
    {
      perror("recvfrom error");
      return -1;
    }
    char* peer_ip = inet_ntoa(peer.sin_addr);
    uint16_t peer_port = ntohs(peer.sin_port);
    printf("[clinet%s:%d] say: %s\n",peer_ip,peer_port,buf);

    // 发送数据
    char data[1024]={0};
    printf("server say: ");
    fflush(stdout);
    scanf("%s",data);

    //将data中的数据发送到peer中，peer为接收数据的地址
    ret = sendto(sockfd,data,strlen(data),0,(struct sockaddr*)&peer,len);
    if(ret<0)
    {
      perror("sendto error");
      return -1;
    }
  }

  //4. 关闭套接字
  close(sockfd);

  return 0;
}
